#include "ulib.h"
#include "giza.h"

CGiza before_st;
CGiza before_ts;
CGiza before_int;

CGiza after_st;
CGiza after_ts;
CGiza after_int;
CGiza after_int_re;

CGiza gold;

class CEval {
public:
	CEval()	{
		Init();
	}
	void Init()	{
		prec = -1;
		recall = -1;
		f = -1;
		num_gold_wa = 0;
		num_giza_wa = 0;
		num_giza_corr_wa = 0;
	}

	float GetPrec()	{
		if( num_giza_wa == 0 )	1;
		return (double)num_giza_corr_wa / (double)num_giza_wa;
	}
	float GetRec()	{
		if( num_gold_wa == 0 )	0;
		return (double)num_giza_corr_wa / (double)num_gold_wa;
	}
	float GetF() {
		if( GetPrec() + GetRec() == 0 )	return 0;
		return 2 * GetPrec() * GetRec() / (GetPrec()+GetRec());
	}

	void Print( char *msg )	{
		fprintf( stdout, "[%s]\n", msg );
		fprintf( stdout, "Prec: %1.4f\n", GetPrec() );
		fprintf( stdout, "Recl: %1.4f\n", GetRec() );
		fprintf( stdout, "F   : %1.4f\n", GetF() );
	}


	float prec;
	float recall;
	float f;
	int num_gold_wa;
	int num_giza_wa;
	int num_giza_corr_wa;
};

bool Init()
{
	if( before_st.Open( "init-st.giza" ) == false )	return false;
	if( before_ts.Open( "init-ts.giza" ) == false )	return false;
	if( before_int.Open( "init-int.giza" ) == false )	return false;

	if( after_st.Open( "i1-st.giza" ) == false )	return false;
	if( after_ts.Open( "i1-ts.giza" ) == false )	return false;
	if( after_int.Open( "i1-int.giza" ) == false )	return false;
	if( after_int_re.Open( "i1-int-rec.giza" ) == false )	return false;

	if( gold.Open( "wa-gold.giza" ) == false )	return false;
}


bool check_giza( CGiza &before, CGiza &after, bool &src, bool &wa )
{
	src = true;
	wa = true;

	if( before.src.tok_list.GetSize() != after.src.tok_list.GetSize() )	return false;
	if( before.align.align_list.GetSize() != after.align.align_list.GetSize() )	return false;
	for( int i=0; i<before.src.tok_list.GetSize(); i++ )	{
		CUString before_src = before.src.tok_list.GetAt(i);
		CUString after_src  = after.src.tok_list.GetAt(i);

		before_src.Replace("\\/", "{#SLASH}" );
		after_src.Replace("\\/", "{#SLASH}" );
		int idx=0;
		idx = before_src.Find("/");
		if( idx >= 0 )	{ before_src = before_src.Left( idx ); }
		idx = after_src.Find("/");
		if( idx >= 0 )	{ after_src = after_src.Left( idx ); }

		if( before_src != after_src )	{
			//fprintf( stderr, "%s\n%s\n", before_src.GetStr(), after_src.GetStr() );
			src = false;
			wa = false;
			break;
		}
	}

	if( wa == true )	{
		for( int i=0; i<before.align.align_list.GetSize(); i++ )	{
			CUString before_align = before.align.align_list.GetAt(i);
			CUString after_align  = after.align.align_list.GetAt(i);
			if( before_align != after_align )	{
				wa = false;
				break;
			}
		}
	}



	return true;
}

bool IsFunc( CUString &str )
{
	return false; 

	if( str.Count("/J" ) == 1 )	return true;
	if( str.Count("/E" ) == 1 )	return true;
	return false;
}

void get_scores( CGiza &gold, CGiza &giza, CEval &sent_eval, CEval &all_eval )
{
	sent_eval.Init();

	for( int i=0; i<gold.align.align_list.GetSize(); i++ )	{
		CUString gold_align = gold.align.align_list.GetAt(i);
		CUString giza_align = giza.align.align_list.GetAt(i);


//		fprintf( stdout, "[%s] [%s]\n", gold_align.GetStr() , giza_align.GetStr() );
		CUStringList gold_align_list;
		gold_align_list.TokenizeByChar( gold_align, " ", false );
		CUStringList giza_align_list;
		giza_align_list.TokenizeByChar( giza_align, " ", false );

//		gold_align_list.PrintEx( stdout, "  " ); fprintf( stdout, "\n" );
//		giza_align_list.PrintEx( stdout, "  " ); fprintf( stdout, "\n" );

		for( int j=0; j<gold_align_list.GetSize(); j++ )	{
			int idx = atoi( gold_align_list.GetAt(j) ) - 1;
			CUString tok = gold.tgt.tok_list.GetAt( idx );
			if( IsFunc( tok ) )	continue;
			sent_eval.num_gold_wa++;
			all_eval.num_gold_wa++;
		}
	
		for( int j=0; j<giza_align_list.GetSize(); j++ )	{
			int idx = atoi( giza_align_list.GetAt(j) ) - 1;
			CUString tok = gold.tgt.tok_list.GetAt( idx );
			if( IsFunc( tok ) )	continue;
			all_eval.num_giza_wa++;
			sent_eval.num_giza_wa++;
		}


		for( int j=0; j<gold_align_list.GetSize(); j++ )	{
			for( int k=0; k<giza_align_list.GetSize(); k++ )	{
				int gold_idx = atoi( gold_align_list.GetAt(j) ) - 1;
				int giza_idx = atoi( giza_align_list.GetAt(k) ) - 1;
				if( gold_idx == giza_idx )	{

					CUString tok = gold.tgt.tok_list.GetAt( gold_idx );
					if( IsFunc( tok ) == true )	{
						continue;
					}


					sent_eval.num_giza_corr_wa++;
					all_eval.num_giza_corr_wa++;

				}

			}
		}
	}
//	fprintf( stdout, "giza %d %d gold %d\n", now_giza_corr_wa, now_giza_wa, now_gold_wa );

}

void print_msg( int num_sent, FILE *fp, CEval &before_eval, CEval &after_eval  )
{
	fprintf( fp, "%d\n", num_sent );
	//fprintf( fp, "gold src: " ); gold.src.tok_list.PrintEx( fp, " " );		 		fprintf( fp, "\n" );
	fprintf( fp, "befo src: " ); before_int.src.tok_list.PrintEx( fp, " " ); 		fprintf( fp, "\n" );
	fprintf( fp, "aftr src: " ); after_int.src.tok_list.PrintEx( fp, " " ); 		fprintf( fp,"\n" );
	fprintf( fp, "tgt:      " ); gold.tgt.tok_list.PrintEx( fp, " " ); 				fprintf( fp,"\n" );
	fprintf( fp, "gold wa:  " ); gold.align.align_list.PrintEx( fp, "   " ); 		fprintf( fp,"\n" );
	fprintf( fp, "befo wa:  " ); before_int.align.align_list.PrintEx( fp, "   " ); 	fprintf( fp,"\n" );
	fprintf( fp, "aftr wa:  " ); after_int.align.align_list.PrintEx( fp, "   " );fprintf( fp, "\n" );
	fprintf( fp, "aftr2wa:  " ); after_int_re.align.align_list.PrintEx( fp, "   " );fprintf( fp, "\n" );
	fprintf( fp, "prec %1.4f (%d/%d)", before_eval.GetPrec(), before_eval.num_giza_corr_wa, before_eval.num_giza_wa );
	fprintf( fp, " ->  %1.4f (%d/%d)\n", after_eval.GetPrec(), after_eval.num_giza_corr_wa, after_eval.num_giza_wa );
	fprintf( fp, "recl %1.4f (%d/%d)", before_eval.GetRec(), before_eval.num_giza_corr_wa, before_eval.num_gold_wa );
	fprintf( fp, " ->  %1.4f (%d/%d)\n", after_eval.GetRec(), after_eval.num_giza_corr_wa, after_eval.num_gold_wa );
	fprintf( fp, "f    %1.4f -> %1.4f", before_eval.GetF(), after_eval.GetF() );
	fprintf( fp, "\n" );
}


bool eval()
{
	fprintf( stderr, "evaluation\n" );
	int num_sent = 0;
	CUTextFile better_file( "ex-better", "w" );
	CUTextFile worse_file( "ex-worse", "w" );
	CUTextFile same_file( "ex-same", "w" );
	CUTextFile prec_file( "stat-prec", "w" );
	CUTextFile rec_file( "stat-rec", "w" );
	CUTextFile f_file( "stat-f", "w" );
	CEval before_eval;
	CEval after_eval;

	while( 1 )	{
		if( before_int.ReadSent() == false )	break;
		if( after_int.ReadSent() == false )	break;
		if( after_int_re.ReadSent() == false )	break;
		if( gold.ReadSent() == false )	break;
		num_sent++;

		if( num_sent > 1000 )	break;

		/*
		bool same_src = false;
		bool same_wa = false;

		if( check_giza( gold, after_int_re, same_src, same_wa ) == false )	{
			fprintf( stderr, "invalid gizas\n" );
		}

		float prec_before = 0;
		float recall_before = 0;
		*/
		CEval now_before_eval; 	get_scores( gold, before_int, now_before_eval, before_eval );
		CEval now_after_eval; 	get_scores( gold, after_int_re, now_after_eval, after_eval );

		if( now_before_eval.GetF() < now_after_eval.GetF() )	{
			print_msg( num_sent, better_file.GetFP(), now_before_eval, now_after_eval );
		}
		else if( now_before_eval.GetF() > now_after_eval.GetF() )	{
			print_msg( num_sent, worse_file.GetFP(), now_before_eval, now_after_eval );
		}

		float ratio = (double)before_int.src.tok_list.GetSize() / (double) before_int.tgt.tok_list.GetSize();
		fprintf( f_file.GetFP(), "%1.4f\t%d\t%d\t%1.4f\n", now_before_eval.GetF(),
				before_int.src.tok_list.GetSize(), before_int.tgt.tok_list.GetSize(), ratio );

		fprintf( prec_file.GetFP(), "%1.4f\t%d\t%d\t%1.4f\n", now_before_eval.GetPrec(),
				before_int.src.tok_list.GetSize(), before_int.tgt.tok_list.GetSize(), ratio );

		fprintf( rec_file.GetFP(), "%1.4f\t%d\t%d\t%1.4f\n", now_before_eval.GetRec(),
				before_int.src.tok_list.GetSize(), before_int.tgt.tok_list.GetSize(), ratio );

	}

	before_eval.Print( "before" );
	after_eval.Print( "after" );
	return true;

}

bool stat()
{
	CUTextFile before_st_src_out( "init-st.giza.src", "w" );
	CUTextFile before_st_tgt_out( "init-st.giza.tgt", "w" );
	CUTextFile before_ts_src_out( "init-ts.giza.src", "w" );
	CUTextFile before_ts_tgt_out( "init-ts.giza.tgt", "w" );
	CUTextFile before_int_src_out( "init-int.giza.src", "w" );
	CUTextFile before_int_tgt_out( "init-int.giza.tgt", "w" );

	CUTextFile after_st_src_out( "i1-st.giza.src", "w" );
	CUTextFile after_st_tgt_out( "i1-st.giza.tgt", "w" );
	CUTextFile after_ts_src_out( "i1-ts.giza.src", "w" );
	CUTextFile after_ts_tgt_out( "i1-ts.giza.tgt", "w" );
	CUTextFile after_int_src_out( "i1-int.giza.src", "w" );
	CUTextFile after_int_tgt_out( "i1-int.giza.tgt", "w" );

	CUTextFile check_lex( "check_lex", "w" );
	int num_sent = 0;
	int num_same_tok = 0;
	int num_same_tok_diff_wa = 0;
	int num_same_tok_same_wa = 0;
	while( 1 )	{
		if( before_st.ReadSent() == false )	break;
		if( before_ts.ReadSent() == false )	break;
		if( before_int.ReadSent() == false )	break;
		if( after_st.ReadSent() == false )	break;
		if( after_ts.ReadSent() == false )	break;
		if( after_int.ReadSent() == false )	break;
		num_sent++;

		if( num_sent > 1000 )	break;

		// st
		before_st.src.tok_list.Print( before_st_src_out.GetFP(), " " ); fprintf( before_st_src_out.GetFP(), "\n" );
		before_st.tgt.tok_list.Print( before_st_tgt_out.GetFP(), " " ); fprintf( before_st_tgt_out.GetFP(), "\n" );

		// ts
		before_ts.src.tok_list.Print( before_ts_src_out.GetFP(), " " ); fprintf( before_ts_src_out.GetFP(), "\n" );
		before_ts.tgt.tok_list.Print( before_ts_tgt_out.GetFP(), " " ); fprintf( before_ts_tgt_out.GetFP(), "\n" );

		// int
		before_int.src.tok_list.Print( before_int_src_out.GetFP(), " " ); fprintf( before_int_src_out.GetFP(), "\n" );
		before_int.tgt.tok_list.Print( before_int_tgt_out.GetFP(), " " ); fprintf( before_int_tgt_out.GetFP(), "\n" );

		// st
		after_st.src.tok_list.Print( after_st_src_out.GetFP(), " " ); fprintf( after_st_src_out.GetFP(), "\n" );
		after_st.tgt.tok_list.Print( after_st_tgt_out.GetFP(), " " ); fprintf( after_st_tgt_out.GetFP(), "\n" );

		// ts
		after_ts.src.tok_list.Print( after_ts_src_out.GetFP(), " " ); fprintf( after_ts_src_out.GetFP(), "\n" );
		after_ts.tgt.tok_list.Print( after_ts_tgt_out.GetFP(), " " ); fprintf( after_ts_tgt_out.GetFP(), "\n" );
		after_int.src.tok_list.Print( after_int_src_out.GetFP(), " " ); fprintf( after_int_src_out.GetFP(), "\n" );
		after_int.tgt.tok_list.Print( after_int_tgt_out.GetFP(), " " ); fprintf( after_int_tgt_out.GetFP(), "\n" );

		bool same_src = false;
		bool same_wa = false;

		if( check_giza( before_int, after_int, same_src, same_wa ) == false )	{
			fprintf( stderr, "invalid gizas\n" );
		}

		if( same_src == true )	{
			num_same_tok++;
			if( same_wa == true )	{
				num_same_tok_same_wa++;
			}
			else	{
				num_same_tok_diff_wa++;
			}


		}

	}


	fprintf( stderr, "same tok: %d sents\n", num_same_tok );
	fprintf( stderr, "same tok same wa : %d sents\n", num_same_tok_same_wa );
	fprintf( stderr, "same tok diff wa : %d sents\n", num_same_tok_diff_wa );
}


bool func1()
{

	if( Init() == false )	{
		fprintf( stderr, "fail to init\n" );
		return false;
	}

	eval();
//	stat();


	return true;	
}


int main( int argc, char *argv[] )
{
	if( argc != 1 )	{
		fprintf( stderr, "usage: wa-inspector\n" );
		return 1;
	}

	if( func1() == false )	{
		return 1;
	}

	return 0;
}

